package com.cqemme.messageservice.service.impl;

import com.cqemme.comm.enums.EnumEmail;
import com.cqemme.comm.po.CurrentLoginUser;
import com.cqemme.comm.po.EmailModelException;
import com.cqemme.comm.utils.JackSonUtils;
import com.cqemme.comm.utils.RegExpValidatorUtils;
import com.cqemme.comm.utils.StringUtils;
import com.cqemme.messageservice.config.EmailProperties;
import com.cqemme.messageservice.feign.UserServiceFeign;
import com.cqemme.messageservice.service.SendEmailService;
import com.cqemme.messageservice.util.JedisUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.regex.Matcher;

/**
 * @author nejery
 */
@Service
@Slf4j
public class SendEmailServiceImpl implements SendEmailService {

    @Resource
    private JavaMailSender mailSender;

    private EmailProperties emailProperties;

    @Resource
    private UserServiceFeign userServiceFeign;

    @Resource
    private MailProperties mailProperties;

    @Resource
    private JedisUtil jedisUtil;

    public SendEmailServiceImpl(EmailProperties emailProperties) {
        this.emailProperties = emailProperties;
    }

    /**
     * 发送者邮箱
     */
    private HashSet<Map<String, String>> senders = new HashSet<>();


    @Override
    public void sendExceptionEmail(EmailModelException emailModel) {
        // 添加 root 用户
        Map<String, String> root = new HashMap<>(2);
        root.put("user", emailProperties.getRootSendUser());
        root.put("email", emailProperties.getRootSendEmail());
        senders.add(root);
        this.getExceptionGroup();
        // 添加URL基本路径
        emailModel.setRequestUrl(emailProperties.getBaseRequestUrl() + emailModel.getRequestUrl());
        sendEmail(emailModel);
    }

    /**
     * 查询异常问题组
     */
    private void getExceptionGroup() {
        String developers = userServiceFeign.getDevelopers("2");
        JsonNode resultSuccessData = JackSonUtils.getResultSuccessData(developers);
        if (resultSuccessData != null) {
            String listString = resultSuccessData.get("list").toString();
            if (StringUtils.isNotBlank(listString)) {
                ArrayNode list = JackSonUtils.transArrayNode(listString);
                if (list != null) {
                    for (JsonNode item : list) {
                        String email = item.get("email").asText();
                        if (RegExpValidatorUtils.isEmail(email)) {
                            Map<String, String> temp = new HashMap<>(2);
                            temp.put("user", item.get("username").asText());
                            temp.put("email", item.get("email").asText());
                            senders.add(temp);
                        }
                    }
                }
            }
        }
    }

    /**
     * 检查是否发送邮件
     * 判断开发环境
     *
     * @return 是否发送邮件
     */
    private boolean checkSendEmail() {
        boolean isSend = true;
        String devString = "dev";
        if (devString.equals(emailProperties.getProjectStatus())) {
            // 只在工作时间发送
            if (emailProperties.isOnlySendWork()) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date date = new Date();
                String strDate = sdf.format(date);
                // 截取当前时间时分
                int stringDateHours = Integer.parseInt(strDate.substring(11, 13));
                int stringDateMinute = Integer.parseInt(strDate.substring(14, 16));
                String curTime = stringDateHours + ":" + stringDateMinute;
                String[] workTimes = emailProperties.getWorkTimes();
                for (String time : workTimes) {
                    // 当前时间在给定的工作时间内
                    if (isInTime(time, curTime)) {
                        isSend = false;
                        break;
                    }
                }
            }
        }

        return isSend;
    }

    /**
     * 判断某一时间是否在一个区间内
     *
     * @param sourceTime 时间区间,半闭合,如[10:00-20:00)
     * @param curTime    需要判断的时间 如10:00
     * @return true 或 false
     */
    private static boolean isInTime(String sourceTime, String curTime) {
        String colon = ":";
        String line = "-";
        if (sourceTime == null || !sourceTime.contains(line) || !sourceTime.contains(colon)) {
            throw new IllegalArgumentException("Illegal Argument arg:" + sourceTime);
        }
        if (curTime == null || !curTime.contains(colon)) {
            throw new IllegalArgumentException("Illegal Argument arg:" + curTime);
        }
        String[] args = sourceTime.split(line);
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        try {
            long now = sdf.parse(curTime).getTime();
            long start = sdf.parse(args[0]).getTime();
            long end = sdf.parse(args[1]).getTime();
            if ("00:00".equals(args[1])) {
                args[1] = "24:00";
            }
            if (end < start) {
                return now < end || now >= start;
            } else {
                return now >= start && now < end;
            }
        } catch (ParseException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("Illegal Argument arg:" + sourceTime);
        }

    }



    /**
     * 获取当前环境
     *
     * @return dev test prod
     */
    private String enumEnvironment() {
        String environment;
        // redis 缓存时间， 多少秒内不发送
        switch (emailProperties.getProjectStatus()) {
            case "dev":
                environment = "开发环境";
                break;
            case "test":
                environment = "测试环境";
                break;
            default:
                environment = "线上环境";
        }
        return environment;
    }


    /**
     * 发送邮件
     *
     * @param emailModel 邮件模型
     */
    private void sendEmail(EmailModelException emailModel) {
        String html = EnumEmail.Html.getState();
        String text = EnumEmail.Text.getState();
        String emailType = emailModel.getEmailType();

        String key = emailModel.getRedisCacheKey();
        String isCache = jedisUtil.get(key);
        if (StringUtils.isEmpty(isCache)) {
            // 发送简单邮件
            if (emailType.equals(text)) {
                sendSimpleEmail(emailModel);
            } else if (emailType.equals(html)) {
                // 发送Html邮件
                try {
                    sendHtmlEmail(emailModel);
                } catch (MessagingException e) {
                    e.printStackTrace();
                }
            }
            // redis 缓存接口记录
            jedisUtil.set(key, "我是一个站位符");
            jedisUtil.expire(key, emailProperties.getSendEmailDelayTime());
//            redisTemplate.expire(key, emailProperties.getSendEmailDelayTime(), TimeUnit.SECONDS);

        }

    }

    /**
     * 发送HTml邮件
     *
     * @param emailModel 邮件模型
     */
    private void sendHtmlEmail(EmailModelException emailModel) throws MessagingException {
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        //是否发送的邮件是富文本（附件，图片，html等）
        MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
        for (Map<String, String> item : senders) {
            messageHelper.setFrom(mailProperties.getUsername());
            messageHelper.setTo(item.get("email"));
            messageHelper.setSubject(emailModel.getSubject() + " : " + emailProperties.getProjectName() + "-" + enumEnvironment());
            messageHelper.setText(handleAndCreateHtml(emailModel), true);
            mailSender.send(mimeMessage);
        }
        log.info("邮件发送成功！！！");
    }

    /**
     * 发送简单邮件
     *
     * @param emailModel 邮件模型
     */
    private void sendSimpleEmail(EmailModelException emailModel) {
        SimpleMailMessage message = new SimpleMailMessage();
        for (Map<String, String> item : senders) {
            message.setFrom(mailProperties.getUsername());
            message.setTo(item.get("email"));
            message.setSubject(emailModel.getSubject() + " : " + emailProperties.getProjectName() + "-" + enumEnvironment());
            message.setText(emailModel.getContent());
            mailSender.send(message);
        }
    }




    /**
     * 替换模板创建html内容
     *
     * @param emailModel 邮件模型
     * @return 替换后的html字符串
     */
    private String handleAndCreateHtml(EmailModelException emailModel) {
        StringBuilder desc = new StringBuilder();
        try {
            InputStream is = this.getClass().getClassLoader().getResourceAsStream("html/ExceptionEmailTemplate.html");
            if (null != is) {
                InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
                BufferedReader br = new BufferedReader(isr);
                String lineTxt;
                while ((lineTxt = br.readLine()) != null) {
                    desc.append(lineTxt);
                }
                br.close();
            }
        } catch (Exception e) {
            log.error("文件错误!" + e.getMessage());
        }

        // 利用反射替换html中所有的值
        Class<? extends EmailModelException> aClass = emailModel.getClass();
        String filedFirstUpper;
        String field;
        Object val;
        String value = "";
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            // 只需要找set方法后面的字段
            if (method.getName().indexOf("get") == 0) {
                filedFirstUpper = method.getName().substring(3);
                field = filedFirstUpper.substring(0, 1).toLowerCase() + filedFirstUpper.substring(1);
                try {
                    val = method.invoke(emailModel);
                    if (null != val) {
                        if (Map.class.isAssignableFrom(val.getClass()) || val.getClass() == CurrentLoginUser.class) {
                            value = JackSonUtils.beanToString(val);
                            // 堆栈信息需要特别处理
                        } else if ("stackTrace".equals(field)) {
                            StackTraceElement[] stackTrace = emailModel.getStackTrace();
                            StringBuilder sb = new StringBuilder();
                            for (StackTraceElement element : stackTrace) {
                                sb.append(element.toString());
                                sb.append("<br/>");
                            }
                            value = sb.toString();
                        } else {
                            value = val.toString();
                        }
                    }
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }

                desc = new StringBuilder(desc.toString().replaceAll("#\\{" + field + "}", Matcher.quoteReplacement(value)));
            }
        }
        return desc.toString();
    }
}
